/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.mail.MessagingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import net.coobird.thumbnailator.Thumbnails;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 *
 * @author Patrick
 */
public class DataManager extends HttpServlet {

    private static final String STATUS_SUCCESS = "<status>SUCCESS</status>";
    private static final String STATUS_USERNAMEEXISTS = "<status>USERNAMEEXISTS</status>";
    private static final String STATUS_FAILED = "<status>FAILED</status>";
    private static final String ROOT_BEGIN = "<crombz>";
    private static final String ROOT_END = "</crombz>";

    private enum ACTIONS {

        SCAN,
        CROMBS,
        POST,
        DISTANCE,
        TRAVELERS,
        NEWS,
        TAGS,
        RESIZEIMAGES,
        LOGIN,
        LOGOUT,
        CREATELOGIN,
        ISLOGGED,
        LIKE,
        TOPCROMBERS,
        LOCALCRIMELIST,
        GLOBALCRIMELIST,
        REPORTCRIME,
        EVENTS,
        POSTEVENT,
        ADDRESSTOLOCATION,
        VERSUS,
    }

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/xml;charset=UTF-8");
        String action = "";
        String lon = "";
        String lat = "";
        String author = "";
        String message = "";
        String userTag = "";
        String content = "";
        String username = "";
        String userpass = "";
        String useremail = "";
        String crombId = "";
        String crimeId = "";
        String eventId = "";
        String eventName = "";
        String eventDuration = "1";
        String address = "";
        String versusId = "";
        String versusVote = "";
        MultipartRequest multi = null;
        if (request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart/form-data")) {
            try {
                multi = new MultipartRequest(request, getInitParameter("imagesPath"), 10 * 1024 * 1024);
                action = multi.getParameter("action");
                lon = multi.getParameter("lon");
                lat = multi.getParameter("lat");
                author = multi.getParameter("author");
                message = multi.getParameter("message");
                userTag = multi.getParameter("tag");
                content = request.getContentType().toLowerCase();
                username = multi.getParameter("username");
                userpass = multi.getParameter("userpass");
                useremail = multi.getParameter("useremail");
                crombId = multi.getParameter("crombid");
                crimeId = multi.getParameter("crimeid");
                eventId = multi.getParameter("eventid");
                eventName = multi.getParameter("eventname");
                eventDuration = multi.getParameter("eventduration");
                address = multi.getParameter("address");
                versusId = multi.getParameter("versusid");
                versusVote = multi.getParameter("versusvote");
            } catch (Exception e) {
                PrintWriter logs = new PrintWriter(getInitParameter("imagesPath") + "/logs.txt");
                e.printStackTrace(logs);
                logs.close();
            }
        } else {
            action = request.getParameter("action");
            lon = request.getParameter("lon");
            lat = request.getParameter("lat");
            author = request.getParameter("author");
            message = request.getParameter("message");
            userTag = request.getParameter("tag");
            username = request.getParameter("username");
            userpass = request.getParameter("userpass");
            useremail = request.getParameter("useremail");
            crombId = request.getParameter("crombid");
            crimeId = request.getParameter("crimeid");
            eventId = request.getParameter("eventid");
            eventName = request.getParameter("eventname");
            eventDuration = request.getParameter("eventduration");
            address = request.getParameter("address");
            versusId = request.getParameter("versusid");
            versusVote = request.getParameter("versusvote");
        }

        PrintWriter out = response.getWriter();
        Connection connection = null;
        HttpSession session = request.getSession();
        session.setMaxInactiveInterval(1800);
        long startTime = System.currentTimeMillis();
        try {
            connection = CrombManager.getConnection(getInitParameter("host"), getInitParameter("db"), getInitParameter("user"), getInitParameter("pass"));
            switch (ACTIONS.valueOf(action.toUpperCase())) {
                case VERSUS:
                    if (versusVote != null && versusVote.length() > 0) {
                        if ("TRUE".equals(session.getAttribute("versusCanVote"))) {
                            session.setAttribute("versusCanVote", "FALSE");
                            if ("LEFT".equals(versusVote)) {
                                VersusManager.voteLeft(connection, new Integer(versusId));
                                System.out.println("Voted left...");
                            } else if ("RIGHT".equals(versusVote)) {
                                VersusManager.voteRight(connection, new Integer(versusId));
                                System.out.println("Voted right...");
                            }
                        }
                    } else {
                        out.print(VersusManager.getXMLVersusList(connection));
                        session.setAttribute("versusCanVote", "TRUE");
                    }
                    break;
                case ADDRESSTOLOCATION:
                    String url = "http://maps.google.com/maps/api/geocode/xml?address=" + URLEncoder.encode(address, "UTF-8") + "&sensor=false";

                    Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(url);
                    NodeList location = doc.getElementsByTagName("location");
                    out.println(ROOT_BEGIN);
                    if (location.getLength() > 0) {
                        String xmllon = "";
                        String xmllat = "";
                        for (int i = 0; i < location.item(0).getChildNodes().getLength(); i++) {
                            Node n = location.item(0).getChildNodes().item(i);
                            if (n.getNodeName().equals("lat")) {
                                xmllat = n.getTextContent();
                            } else if (n.getNodeName().equals("lng")) {
                                xmllon = n.getTextContent();
                            }
                        }
                        out.println("<location lon='" + xmllon + "' lat='" + xmllat + "'>"
                                + "</location>");
                    }
                    out.println(ROOT_END);
                    break;
                case EVENTS:
                    out.println(ROOT_BEGIN);
                    out.println(EventManager.getXMLEventList(connection, new Double(lon), new Double(lat)));
                    out.println(STATUS_SUCCESS);
                    out.println(ROOT_END);
                    break;
                case POSTEVENT:
                    out.println(ROOT_BEGIN);
                    if (eventId != null && eventName != null) {
                        if (eventName.length() > 0 && eventId.length() > 0) {
                            if (eventDuration == null || eventDuration.length() == 0) {
                                eventDuration = "1";
                            }
                            java.sql.Date endingDate = new java.sql.Date(System.currentTimeMillis() + (new Long(eventDuration) * 1000 * 3600 * 24));
                            EventManager.postEvent(connection, new Integer(eventId), eventName, new Double(lon), new Double(lat), endingDate);
                            out.println(STATUS_SUCCESS);
                        }
                    }
                    out.println(ROOT_END);
                    break;
                case LIKE:
                    out.println(ROOT_BEGIN);
                    if (crombId != null && crombId.length() > 0) {
                        CrombManager.updateCrombLikeCounter(connection, new Integer(crombId));
                    }
                    out.println(STATUS_SUCCESS);
                    out.println(ROOT_END);
                    break;
                case ISLOGGED:
                    out.println(ROOT_BEGIN);
                    if (session.getAttribute("user") != null) {
                        User user = (User) session.getAttribute("user");
                        out.println("<user name='" + user.userName + "' email='" + user.email + "'/>");
                        out.println(STATUS_SUCCESS);
                    } else {
                        out.println(STATUS_FAILED);
                    }
                    out.println(ROOT_END);
                    break;
                case CREATELOGIN:
                    out.println(ROOT_BEGIN);
                    if (username != null && useremail != null) {
                        if (username.length() > 0 && useremail.length() > 0) {
                            User user = UserManager.updateCrombUser(connection, username, useremail, getInitParameter("mailhost"), new Integer(getInitParameter("mailport")), getInitParameter("mailuser"), getInitParameter("mailpassword"));
                            if (user.userID >= 0) {
                                out.println(STATUS_SUCCESS);
                            } else if (user.userID == -2) {
                                out.println(STATUS_USERNAMEEXISTS);
                            } else {
                                out.println(STATUS_FAILED);
                            }
                        }
                    }
                    out.println(ROOT_END);
                    break;
                case LOGIN:
                    out.println(ROOT_BEGIN);
                    if (useremail != null && userpass != null) {
                        User user = UserManager.getUser(connection, useremail, userpass);
                        if (user != null && user.userID >= 0) {
                            session.setAttribute("user", user);
                            out.println("<user name='" + user.userName + "' email='" + useremail + "'/>");
                            out.println(STATUS_SUCCESS);
                        } else {
                            session.removeAttribute("user");
                            out.println(STATUS_FAILED);
                        }
                    }
                    out.println(ROOT_END);
                    break;
                case LOGOUT:
                    out.println(ROOT_BEGIN);
                    session.removeAttribute("user");
                    out.println(STATUS_SUCCESS);
                    out.println(ROOT_END);
                    break;
                case SCAN:
                    out.print(CrombManager.getXMLCount(connection, Double.parseDouble(lon), Double.parseDouble(lat)));
                    break;
                case CROMBS:
                    out.print(CrombManager.getXMLCrombs(connection, Double.parseDouble(lon), Double.parseDouble(lat)));
                    break;
                case DISTANCE:
                    out.print(CrombManager.getXMLDistance(connection, Double.parseDouble(lon), Double.parseDouble(lat)));
                    break;
                case POST:
                    out.println(ROOT_BEGIN);
                    int userId = -1;
                    if (session.getAttribute("user") != null) {
                        User u = (User) session.getAttribute("user");
                        userId = u.userID;
                    }
                    File image = null;

                    if (multi != null) {
                        Enumeration en = multi.getFileNames();
                        if (en != null) {
                            while (en.hasMoreElements()) {
                                String name = en.nextElement().toString();
                                String filename = multi.getFilesystemName(name);
                                String type = multi.getContentType(name);
                                image = multi.getFile(name);
                                if (!resizeImage(image)) {
                                    image = null;
                                }
                            }
                        }
                    }
                    CrombManager.putCromb(connection, Double.parseDouble(lon), Double.parseDouble(lat), author, message, image, userId);
                    out.println(STATUS_SUCCESS);
                    out.println(ROOT_END);
                    break;
                case TRAVELERS:
                    TravelerManager.moveTravelers(connection);
                    break;
                case NEWS:
                    out.print(NewsManager.getXMLNews(connection));
                    break;
                case TAGS:
                    out.print(CrombManager.getXMLTagList(connection, Double.parseDouble(lon), Double.parseDouble(lat), userTag));
                    break;
                case RESIZEIMAGES:
                    out.println(ROOT_BEGIN);
                    for (File f : new File(getInitParameter("imagesPath")).listFiles()) {
                        if (f.isFile()) {
                            out.println("<file>" + f.getName() + "</file>");
                            try {
                                BufferedImage img = ImageIO.read(f);
                                out.println(STATUS_SUCCESS);
                                BufferedImage resized = new BufferedImage(50, 50, img.getType());
                                Graphics2D g = resized.createGraphics();
                                g.drawImage(img.getScaledInstance(50, 50, BufferedImage.SCALE_FAST), 0, 0, null);
                                g.dispose();
                                if (f.getName().endsWith("jpg")) {
                                    FileOutputStream imgOut = new FileOutputStream(f);
                                    ImageIO.write(resized, "jpg", imgOut);
                                    imgOut.flush();
                                    imgOut.close();
                                } else if (f.getName().endsWith("png")) {
                                    FileOutputStream imgOut = new FileOutputStream(f);
                                    ImageIO.write(resized, "png", imgOut);
                                    imgOut.flush();
                                    imgOut.close();
                                } else if (f.getName().endsWith("gif")) {
                                    FileOutputStream imgOut = new FileOutputStream(f);
                                    ImageIO.write(resized, "gif", imgOut);
                                    imgOut.flush();
                                    imgOut.close();
                                } else {
                                    f.delete();
                                }

                            } catch (Exception e) {
                                f.delete();
                                e.printStackTrace(out);
                            }
                        }
                    }
                    out.println(ROOT_END);
                    break;
                case TOPCROMBERS:
                    out.println(UserManager.getXMLTopCrombers(connection));
                    break;
                case LOCALCRIMELIST:
                    out.println(CrimeManager.getXMLCrimeList(connection, new Double(lon), new Double(lat), false));
                    break;
                case GLOBALCRIMELIST:
                    out.println(CrimeManager.getXMLCrimeList(connection, new Double(lon), new Double(lat), true));
                    break;
                case REPORTCRIME:
                    out.println(ROOT_BEGIN);
                    if (crimeId != null && crimeId.length() > 0 && lon != null && lat != null) {
                        CrimeManager.reportCrime(connection, new Integer(crimeId), new Double(lon), new Double(lat));
                    }
                    out.println(STATUS_SUCCESS);
                    out.println(ROOT_END);
                    break;
            }
        } catch (SQLException ex) {
            out.println("<status>" + ex.getMessage());
            ex.printStackTrace(out);
            out.println("</status>");
        } catch (ParserConfigurationException ex) {
            out.println("<status>" + ex.getMessage());
            ex.printStackTrace(out);
            out.println("</status>");
        } catch (TransformerConfigurationException ex) {
            out.println("<status>" + ex.getMessage());
            ex.printStackTrace(out);
            out.println("</status>");
        } catch (TransformerException ex) {
            out.println("<status>" + ex.getMessage());
            ex.printStackTrace(out);
            out.println("</status>");
        } catch (MessagingException ex) {
            out.println("<status>" + ex.getMessage());
            ex.printStackTrace(out);
            out.println("</status>");
        } catch (SAXException ex) {
            Logger.getLogger(DataManager.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException ex) {
                    out.println("<status>" + ex.getMessage() + "</status>");
                }
            }
            out.close();
        }
        System.out.println("Request Time: " + action + " - " + (System.currentTimeMillis() - startTime) + "ms");
    }

    private boolean resizeImage(File f) {
        boolean retValue = true;
        if (f != null) {
            try {
                Thumbnails.of(f).size(50, 50).toFile(f);
            } catch (Exception e) {
                f.delete();
                retValue = false;
            }
        }
        return retValue;
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Crombz DataManager";
    }// </editor-fold>
}
